package com.study.support;

import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;

import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import java.util.Set;

public class ClasspathScanningPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor, ResourceLoaderAware, EnvironmentAware {

    private static final Logger LOG = LoggerFactory.getLogger(ClasspathScanningPersistenceUnitPostProcessor.class);

    private Environment environment;

    private ResourceLoader resourceLoader;

    private final String basePackage;

    private ClasspathScanningPersistenceUnitPostProcessor(String basePackage){
        Assert.hasText(basePackage, "Base package must not be null or empty!");
        this.basePackage = basePackage;
    }

    @Override
    public void setEnvironment(@NotNull Environment environment) {
        Assert.notNull(resourceLoader, "ResourceLoader must not be null!");
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(@NotNull ResourceLoader resourceLoader) {
        Assert.notNull(environment, "Environment must not be null!");
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui){
        LOG.info("Scanning for entities in package: " + basePackage);
        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.setEnvironment(environment);
        provider.setResourceLoader(resourceLoader);
        provider.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
        provider.addIncludeFilter(new AnnotationTypeFilter(MappedSuperclass.class));
        Set<BeanDefinition> components = provider.findCandidateComponents(basePackage);
        components.forEach(beanDefinition -> {
            String className = beanDefinition.getBeanClassName();
            pui.addManagedClassName(className);
        });
    }
}
